
// Copyright (c) 2012, 2013 All Right Reserved, http://hpc.utp.edu.my
// Author: Nordin Zakaria nordinzakaria@gmail.com
// All rights reserved.

#include <stdlib.h>
#include <string>
#include <stdio.h>

#include <map>
#include <vector>
#include <sstream>
using namespace std;

#include "JobAssigned.h"
#include "Random.h"

#ifndef WORKER_CLASS
#define WORKER_CLASS

class Worker;

typedef void (*PreStep)(Worker &);
typedef void (*Step)(Worker &);
typedef void (*PostStep)(Worker &);
typedef void (*WorkerInitialize)(Worker &, unsigned int NumJobs);

//! this class represents a single worker agent.
class Worker
	{
	protected:

	//! Prestep method
	PreStep prestepM;

	//! Step method
	Step stepM;

	//! PostStep method
	PostStep poststepM;

	//! Initialize method
	WorkerInitialize initM;

	//! the identity number of the worker.
	unsigned int id;

	//! array of properties
	vector<int> properties;

	//! the list of jobs assigned to the worker
	vector<JobAssigned> jobList;

	public:

	//! A default constructor that does nothing.
	Worker(){}

	//! A constructor that initializes the id
	/*!
		\param id	the id of the worker
	*/
	Worker(unsigned int id) {
		this->id = id;
		}

	//! A constructor that initializes the id and the number of properties
	/*!
		\param id	the id of the worker
		\param size	the number of properties
	*/
	Worker(unsigned int id, unsigned int size) {
		this->id = id;
		properties.resize(size);
		}

	//! Copy constructor 
	/*!
		\param other	the worker object to copy from
	*/
	Worker(const Worker& other)
		{
		copy(other);
		}

	//! Copy from another object to this object
	/*!
		\param other	the worker object to copy from
	*/
	void copy(const Worker &other);

	//! Clone the object 
	/*!
		\return  a pointer to the cloned object
	*/
	Worker* clone() const {
	        return new Worker(*this);
		}

	//! Assign another object to this object 
	Worker& operator=(const Worker& arg) {
                copy(arg);
                return *this;
                }

	//! set the value of a property
	/*!
		\param prop		the value
		\param index		the index
	*/
    	void set(unsigned int prop, unsigned int index)
	{
		properties[index] = prop;
	}

	//! get the value of a property
	/*!
		\param index		the index
		\return 		the value
	*/
    	unsigned int get(unsigned int index) const
	{
		return properties[index];
	}

	//! set the number of properties for this object
	/*!
		\param sz		the number of properties
	*/
	void properties_size(unsigned int sz) 
	{
		properties.resize(sz);
	}

	//! get the number of properties for this object
	/*!
		\return  the number of properties
	*/
	unsigned int properties_size() const
	{
		return properties.size();
	}


	//! A function for adding a Job
	/*!
		\param job	a JobAssigned object
	*/
	void addJob(JobAssigned &job)
		{
		jobList.push_back(job);
		}

	//! get a job
	/*!
		\param i		the index
	*/
	JobAssigned& getJob(int i)
		{
		return jobList[i];
		}

	//! A function for getting the number of jobs assigned to the worker.
	/*!
		\return the number of jobs assigned to the worker
	*/
	unsigned int getNumJobs()
		{
		return jobList.size();
		}

	//! copy current jobs into another job
	void copyJobsInto(Worker& worker) const
		{
		for (unsigned int i=0; i<jobList.size(); i++)
			{
			JobAssigned job = jobList[i];
			worker.addJob(job);
			}
		}

	//! A function for setting the Id of a worker
	/*!
		\param id		the id of the worker
	*/
	void setID(unsigned int id)
		{
		this->id = id;
		}

	//! A function for getting the id of a worker.
	/*!
		\return the id
	*/
	unsigned int getID() {
		return id;
		}

	//! read job object from a binary file
	/*!
	    \param infile   the input file
	*/
	void read(FILE *infile);

	//! write job object to a binary file
	/*!
	    \param outfile   the output file
	*/
	void write(FILE *outfile);

	//! Overloaded operator for output to a stream
    	friend ostream& operator<<(ostream& os, const Worker& obj);

	//! Overloaded operator for input from a stream
	friend istream& operator>>(istream& is, Worker& obj); 

	//! set the method to be used for prestepping
	/*!
	    \param op   the method
	*/
	PreStep set_prestep(PreStep op) {
        	return (prestepM=op);
        	}

	//! get the method to be used for prestepping
	/*!
	    \return the method
	*/
	PreStep get_prestep() const {
        	return prestepM;
        	}

	//! perform prestepping
	void prestep() {
        	(*prestepM)(*this);	
        	}

	//! set the method to be used for poststepping
	/*!
	    \param op   the method
	*/
	PostStep set_poststep(PostStep op) {
        	return (poststepM=op);
        	}

	//! get the method to be used for poststepping
	/*!
	    \return the method
	*/
	PostStep get_poststep() const {
        	return poststepM;
        	}

	//! perform poststepping
	void poststep() {
        	(*poststepM)(*this);	
        	}

	//! set the method to be used for stepping
	/*!
	    \param op   the method
	*/
	Step set_step(Step op) {
        	return (stepM=op);
        	}

	//! get the method to be used for stepping
	/*!
	    \return the method
	*/
	Step get_step() const {
        	return stepM;
        	}

	//! perform a step
	void step() {
        	(*stepM)(*this);
        	}

	//! set the method to be used for initialization
	/*!
	    \param op   the method
	*/
	WorkerInitialize set_init(WorkerInitialize op) {
        	return (initM=op);
        	}

	//! get the method to be used for initialization
	/*!
	    \return the method
	*/
	WorkerInitialize get_init() const {
        	return initM;
        	}

	//! perform initialization
	/*!
		\param NumJobs the total number of jobs in the simulation
	*/
	void init(const int NumJobs) {
        	(*initM)(*this, NumJobs);
        	}
	};

#endif

